home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / util / text / words3.lha / Words / WarpSPELL / source / funcs.c < prev    next >
C/C++ Source or Header  |  1995-08-28  |  15KB  |  605 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  WarpSPELL ©1995 Dietmar Eilert
  4.  
  5.  Spell checking syntax parser. Dice:
  6.  
  7.  DMAKE
  8.  
  9.  -------------------------------------------------------------------------------
  10.  
  11. */
  12.  
  13. #include "defs.h"
  14.  
  15. /// "Header stuff"
  16.  
  17. // Buffer handles are allocated for each text buffer to keep track of ressources:
  18.  
  19. struct BufferHandle {
  20.  
  21.     struct EditConfig     *bh_EditConfig;            // pointer to text data
  22.     struct GlobalConfig   *bh_GlobalConfig;          // editor configuration
  23.     struct SyntaxChunk    *bh_SyntaxStack;           // parser output
  24.     struct RefreshRequest  bh_RefreshRequest;        // display refresh request
  25.     UBYTE                  bh_Command[4096];         // ISpell command buffer
  26.     UBYTE                  bh_Results[4096];         // ISpell result buffer
  27.     struct MsgPort        *bh_Port;                  // ISpell reply port
  28. };
  29.  
  30. #define EMPTY_STACK ((struct SyntaxChunk *)~0)       // empty stack flag
  31.  
  32. ///
  33. /// "Prototype"
  34.  
  35. // library functions
  36.  
  37. Prototype LibCall struct ParserData     *MountScanner(void);
  38. Prototype LibCall ULONG                  StartScanner(__A0 struct GlobalConfig *, __A1 struct EditConfig *, __D0 struct SyntaxChunk *);
  39. Prototype LibCall ULONG                  CloseScanner(__D0 ULONG);
  40. Prototype LibCall void                   FlushScanner(__D0 ULONG);
  41. Prototype LibCall void                   SetupScanner(__A0 struct GlobalConfig  *);
  42. Prototype LibCall struct RefreshRequest *BriefScanner(__D0 ULONG, __A0 struct ScannerNotify *);
  43. Prototype LibCall struct SyntaxChunk    *ParseLine   (__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  44. Prototype LibCall void                   UnparseLines(__A0 struct LineNode *, __D0 ULONG);
  45. Prototype LibCall void                   ParseSection(__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  46.  
  47. // private functions
  48.  
  49. Prototype struct SyntaxChunk *ParseString(UBYTE *, UWORD, ULONG);
  50. Prototype struct SyntaxChunk *DupStack(struct SyntaxChunk *);
  51. Prototype ULONG              *SendRexxCommand(UBYTE *, UBYTE *, struct MsgPort *replyPort, UBYTE *);
  52. Prototype BOOL                CheckThisWord(ULONG, UBYTE *, UWORD);
  53. Prototype void                AlertInfo(UBYTE *);
  54.  
  55. ///
  56. /// "Globals"
  57.  
  58. BOOL IsLetter[256];
  59. BOOL IsAlNum [256];
  60.  
  61. ///
  62. /// "Library functions"
  63.  
  64. /* ------------------------------- MountScanner --------------------------------
  65.  
  66.  Called by the editor before first usage of a scanner. Return a description of
  67.  our abilities.
  68.  
  69. */
  70.  
  71. __geta4 LibCall struct ParserData *
  72. MountScanner()
  73. {
  74.     static UBYTE version[] = "$VER: WarpSPELL 2.0 (" __COMMODORE_DATE__ ")";
  75.  
  76.     static struct ParserData parserData;
  77.  
  78.     UWORD ascii;
  79.  
  80.     // syntax elements understood by parser
  81.  
  82.     static UBYTE *levelNames[] = { "Standard text", "Spelling error", NULL };
  83.  
  84.     static UBYTE *example[] = {
  85.  
  86.         "Aaron      ",
  87.         "aback      ",
  88.         "abandon    ",
  89.         "abase      ",
  90.         "abash      ",
  91.         "abate      ",
  92.         "abatement  ",
  93.         "abbe       ",
  94.         "abbess     ",
  95.         "abbey      ",
  96.         "abbot      ",
  97.         "abbreviate ",
  98.         "abdicate   ",
  99.         "abdominal  ",
  100.         "abduct     ",
  101.         "adenoids   ",
  102.         "already    ",
  103.         "alsatian   ",
  104.         "also       ",
  105.         "altar      ",
  106.         "alter      ",
  107.  
  108.         NULL
  109.     };
  110.  
  111.     // color suggestions
  112.  
  113.     static ULONG *levelColors[] = {
  114.  
  115.         MAKE_RGB4(0,  0,  0),
  116.         MAKE_RGB4(15, 15, 0),
  117.     };
  118.  
  119.     parserData.pd_Release  = SCANLIBVERSION;
  120.     parserData.pd_Version  = 1;
  121.     parserData.pd_Serial   = 0;
  122.     parserData.pd_Info     = "WarpSPELL 2.0";
  123.     parserData.pd_Levels   = 2;
  124.     parserData.pd_Names    = levelNames;
  125.     parserData.pd_Colors   = levelColors;
  126.     parserData.pd_Flags    = SCPRF_SYNTAXCACHE;
  127.     parserData.pd_Example  = example;
  128.  
  129.     //  preset globals
  130.  
  131.     for (ascii = 0; ascii < 256; ++ascii)
  132.         IsLetter[ascii] = ((ascii >= 'A') && (ascii <= 'Z')) || ((ascii >= 'a') && (ascii <= 'z')) || (ascii >= 'À');
  133.  
  134.     for (ascii = 0; ascii < 256; ++ascii)
  135.         IsAlNum[ascii]  = ((ascii >= '0') && (ascii <= '9')) || IsLetter[ascii];
  136.  
  137.     return(&parserData);
  138. }
  139.  
  140.  
  141. /* ------------------------------- StartScanner --------------------------------
  142.  
  143.  Called by the editor after a new text buffer has been created. We allocate a
  144.  buffer to hold text-specific data. The buffer address is returned as handle.
  145.  
  146. */
  147.  
  148. LibCall ULONG
  149. StartScanner(__A0 struct GlobalConfig *globalConfigPtr, __A1 struct EditConfig *editConfigPtr, __D0 struct SyntaxChunk *syntaxStack)
  150. {
  151.     struct BufferHandle *handle;
  152.  
  153.     if (handle = AllocVec(sizeof(struct BufferHandle), MEMF_PUBLIC | MEMF_CLEAR)) {
  154.  
  155.         if (handle->bh_Port = CreateMsgPort()) {
  156.  
  157.             handle->bh_GlobalConfig = globalConfigPtr;
  158.             handle->bh_EditConfig   = editConfigPtr;
  159.             handle->bh_SyntaxStack  = syntaxStack;
  160.  
  161.             return((ULONG)handle);
  162.         }
  163.         else
  164.             FreeVec(handle);
  165.     }
  166.  
  167.     return(NULL);
  168. }
  169.  
  170.  
  171. /* ------------------------------- CloseScanner --------------------------------
  172.  
  173.  Called by the editor if a text buffer is about to be closed. Deallocate buffer
  174.  specific 'global' data.
  175.  
  176. */
  177.  
  178. LibCall ULONG
  179. CloseScanner(__D0 ULONG scanID)
  180. {
  181.     if (scanID) {
  182.  
  183.         struct BufferHandle *handle = (struct BufferHandle *)scanID;
  184.  
  185.         if (handle->bh_Port)
  186.             DeleteMsgPort(handle->bh_Port);
  187.  
  188.         FreeVec(handle);
  189.     }
  190.  
  191.     return(0);
  192. }
  193.  
  194.  
  195. /* ------------------------------- FlushScanner --------------------------------
  196.  
  197.  Called by the editor in low memory situations: we are supposed to free as much
  198.  memory as possible.
  199.  
  200. */
  201.  
  202. LibCall void
  203. FlushScanner(__D0 ULONG scanID)
  204. {
  205.     struct BufferHandle *handle;
  206.     struct EditConfig   *config;
  207.     struct LineNode     *lineNode;
  208.  
  209.     handle = (struct BufferHandle *)scanID;
  210.     config = handle->bh_EditConfig;
  211.  
  212.     if (lineNode = config->TextNodes)
  213.         UnparseLines(lineNode, config->Lines);
  214. }
  215.  
  216.  
  217. /* ------------------------------- SetupScanner --------------------------------
  218.  
  219.  Called by the editor if the user wants to change the scanner's configuration.
  220.  We do not support user configuration (parserData.pd_Flags: SCPRF_CONFIGWIN flag
  221.  unset).
  222.  
  223. */
  224.  
  225. LibCall void
  226. SetupScanner(__A0 globalConfigPtr)
  227. {
  228.     ;
  229. }
  230.  
  231.  
  232. /* ------------------------------- BriefScanner --------------------------------
  233.  
  234.  Called to notify a context scanner if lines have been added, deleted or
  235.  modified. We aren't a context scanner (parserData.pd_Flags: SCPRF_CONTEXT
  236.  flag unset), so we won't ever have to request additional display requests:
  237.  the editor's built-in refresh of damage regions is sufficient.
  238.  
  239. */
  240.  
  241. LibCall struct RefreshRequest *
  242. BriefScanner(__D0 ULONG scanID, __A0 struct ScannerNotify *notify)
  243. {
  244.     return(NULL);
  245. }
  246.  
  247.  
  248. /* --------------------------------- ParseLine ---------------------------------
  249.  
  250.  Parse a line, build a syntax description
  251.  
  252. */
  253.  
  254. LibCall struct SyntaxChunk *
  255. ParseLine(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG line)
  256. {
  257.     if (lineNode->Fold)
  258.  
  259.         return(NULL);
  260.  
  261.     else if (lineNode->Len) {
  262.  
  263.         // line not yet parsed ?
  264.  
  265.         if (lineNode->UserData == NULL) {
  266.  
  267.             struct SyntaxChunk *syntaxStack = ParseString(lineNode->Text, lineNode->Len, scanID);
  268.  
  269.             if (syntaxStack == EMPTY_STACK)
  270.                 lineNode->UserData = EMPTY_STACK;
  271.             else
  272.                 lineNode->UserData = DupStack(syntaxStack);
  273.         }
  274.  
  275.         if (lineNode->UserData == EMPTY_STACK)
  276.             return((struct SyntaxChunk *)NULL);
  277.         else
  278.             return((struct SyntaxChunk *)lineNode->UserData);
  279.     }
  280.     else
  281.         return(NULL);
  282. }
  283.  
  284. /* -------------------------------- UnparseLines -------------------------------
  285.  
  286.  Called by the editor if lines are to be deleted. We are supposed to free
  287.  private data attached to the lines.
  288.  
  289. */
  290.  
  291. LibCall void
  292. UnparseLines(__A0  struct LineNode *lineNode, __D0 ULONG lines)
  293. {
  294.     while (lines--) {
  295.  
  296.         // free syntax cache
  297.  
  298.         if (lineNode->UserData) {
  299.  
  300.             if (lineNode->UserData != (APTR)EMPTY_STACK)
  301.                 FreeVec((APTR)lineNode->UserData);
  302.  
  303.             lineNode->UserData = NULL;
  304.         }
  305.  
  306.         // free folded subblock
  307.  
  308.         if (lineNode->Fold)
  309.             UnparseLines(lineNode->Fold->TextNodes, lineNode->Fold->Lines);
  310.  
  311.         ++lineNode;
  312.     }
  313. }
  314.  
  315. /* -------------------------------- ParseSection -------------------------------
  316.  
  317.  Called by the editor if lines are to be displayed. The scanner is encouraged to
  318.  preparse the lines.
  319.  
  320. */
  321.  
  322. LibCall void
  323. ParseSection(__D0 ULONG scanID, __A0  struct LineNode *lineNode, __D1 ULONG lines)
  324. {
  325.     while (lines--) {
  326.  
  327.         // fold headers have to be ignored
  328.  
  329.         if (lineNode->Fold == NULL) {
  330.  
  331.             // line not yet parsed ?
  332.  
  333.             if (lineNode->Len)
  334.                 if (lineNode->UserData == NULL)
  335.                     lineNode->UserData = DupStack(ParseString(lineNode->Text, lineNode->Len, scanID));
  336.         }
  337.  
  338.         ++lineNode;
  339.     }
  340. }
  341.  
  342. ///
  343. /// "private"
  344.  
  345. /* -------------------------------- ParseString --------------------------------
  346.  
  347.  Parse a string, build a syntax description. This is a simple example only:
  348.  C++-Comments (// ....) are highlighted. Return EMPTY_STACK in case there is
  349.  nothing to highlight.
  350.  
  351. */
  352.  
  353. struct SyntaxChunk *
  354. ParseString(UBYTE *text, UWORD len, ULONG scanID)
  355. {
  356.     if (len) {
  357.  
  358.         struct SyntaxChunk *syntaxStack = ((struct BufferHandle *)scanID)->bh_SyntaxStack;
  359.  
  360.         UWORD indent, elements, wordLen;
  361.  
  362.         elements = 0;
  363.  
  364.         // leading spaces have to be ignored
  365.  
  366.         for (indent = 0; len && (*text == 32); ++indent, --len)
  367.             ++text;
  368.  
  369.         // trailing spaces have to be ignored
  370.  
  371.         while (len && (text[len - 1] == 32))
  372.             --len;
  373.  
  374.         // check every word of this line
  375.  
  376.         while (len) {
  377.  
  378.             // ignore spaces
  379.  
  380.             while (len && (IsLetter[*text] == FALSE)) {
  381.  
  382.                 ++text;
  383.                 ++indent;
  384.                 --len;
  385.             }
  386.  
  387.             if (len) {
  388.  
  389.                 // get next word
  390.  
  391.                 wordLen = 1;
  392.  
  393.                 while (IsAlNum[text[wordLen]] && (wordLen < len))
  394.                     ++wordLen;
  395.  
  396.                 // check word
  397.  
  398.                 if (CheckThisWord(scanID, text, wordLen)) {
  399.  
  400.                     // highlight word
  401.  
  402.                     syntaxStack[elements].sc_Start = indent;
  403.                     syntaxStack[elements].sc_End   = indent + (wordLen - 1);
  404.                     syntaxStack[elements].sc_Level = 1;
  405.  
  406.                     ++elements;
  407.                 }
  408.  
  409.                 // move to next word
  410.  
  411.                 text   += wordLen;
  412.                 indent += wordLen;
  413.                 len    -= wordLen;
  414.             }
  415.         }
  416.  
  417.         if (elements) {
  418.  
  419.             // terminate syntax stack
  420.  
  421.             syntaxStack[elements].sc_Start = FALSE;
  422.             syntaxStack[elements].sc_End   = FALSE;
  423.             syntaxStack[elements].sc_Level = FALSE;
  424.  
  425.             return(syntaxStack);
  426.  
  427.         }
  428.     }
  429.  
  430.     return(EMPTY_STACK);
  431. }
  432.  
  433. /* --------------------------------- DupStack ----------------------------------
  434.  
  435.  Duplicate syntax stack (to be FreeVec'ed). Return NULL in case of failure.
  436.  
  437. */
  438.  
  439. struct SyntaxChunk *
  440. DupStack(syntaxStack)
  441.  
  442. struct SyntaxChunk *syntaxStack;
  443. {
  444.     if (syntaxStack && (syntaxStack != EMPTY_STACK)) {
  445.  
  446.         struct SyntaxChunk *chunk;
  447.         UWORD               elements;
  448.  
  449.         // determine stack size
  450.  
  451.         for (elements = 0, chunk = syntaxStack; chunk->sc_Level; ++chunk)
  452.             ++elements;
  453.  
  454.         // create copy of syntax stack (to be attached to a text line by the caller)
  455.  
  456.         if (elements) {
  457.  
  458.             ULONG size = (++elements) * sizeof(struct SyntaxChunk);
  459.  
  460.             chunk = syntaxStack;
  461.  
  462.             if (syntaxStack = AllocVec(size, MEMF_PUBLIC))
  463.                 movmem(chunk, syntaxStack, size);
  464.         }
  465.         else
  466.             syntaxStack = EMPTY_STACK;
  467.     }
  468.  
  469.     return(syntaxStack);
  470. }
  471.  
  472. /* ------------------------------- CheckThisWord -------------------------------
  473.  
  474.  Check word <check> of length <len>. Return TRUE if word is not known. Ignore
  475.  single letters.
  476.  
  477. */
  478.  
  479. __geta4 BOOL
  480. CheckThisWord(scanID, check, len)
  481.  
  482. UBYTE  *check;
  483. UWORD   len;
  484. ULONG   scanID;
  485. {
  486.     if (len > 1) {
  487.  
  488.         struct BufferHandle *handle = (struct BufferHandle *)scanID;
  489.  
  490.         UBYTE *command = handle->bh_Command;
  491.  
  492.         strcpy(command, "QUICKCHECK ");
  493.  
  494.         movmem(check, command + 11, len);
  495.  
  496.         command[len + 11] = 0;
  497.  
  498.         // make ISpell check command
  499.  
  500.         if (SendRexxCommand("IRexxSpell", command, handle->bh_Port, handle->bh_Results)) {
  501.  
  502.             if (stricmp(handle->bh_Results, "ok"))
  503.                 return(TRUE);
  504.             else
  505.                 return(FALSE);
  506.         }
  507.     }
  508.     else
  509.         return(FALSE);
  510. }
  511.  
  512. /* ---------------------------------- SendRexxCommand -------------------------
  513.  
  514.  Send ARexx message & wait for answer. Return pointer to result or NULL.
  515.  
  516. */
  517.  
  518. __geta4 ULONG *
  519. SendRexxCommand(port, cmd, replyPort, buffer)
  520.  
  521. struct MsgPort *replyPort;
  522. UBYTE          *cmd, *port, *buffer;
  523. {
  524.     struct MsgPort *rexxport;
  525.  
  526.     Forbid();
  527.  
  528.     if (rexxport = FindPort(port)) {
  529.  
  530.         struct RexxMsg *rexxMsg, *answer;
  531.  
  532.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  533.  
  534.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  535.  
  536.                 static ULONG result;
  537.  
  538.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  539.  
  540.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  541.  
  542.                 do {
  543.  
  544.                     WaitPort(replyPort);
  545.  
  546.                     if (answer = (struct RexxMsg *)GetMsg(replyPort))
  547.                         result = answer->rm_Result1;
  548.  
  549.                 } while (!answer);
  550.  
  551.                 Permit();
  552.  
  553.                 if (answer->rm_Result1 == RC_OK) {
  554.  
  555.                     if (answer->rm_Result2) {
  556.  
  557.                         if (buffer)
  558.                             strcpy(buffer, (char *)answer->rm_Result2);
  559.  
  560.                         DeleteArgstring((char *)answer->rm_Result2);
  561.                     }
  562.                 }
  563.  
  564.                 DeleteArgstring((char *)ARG0(answer));
  565.  
  566.                 DeleteRexxMsg(answer);
  567.  
  568.                 return(&result);
  569.             }
  570.         }
  571.     }
  572.  
  573.     Permit();
  574.  
  575.     return(NULL);
  576. }
  577.  
  578. /* --------------------------------- AlertInfo -----------------------------------
  579.  
  580.  Show alert. Returns TRUE if user pressed left button.
  581.  
  582. */
  583.  
  584. __geta4 void
  585. AlertInfo(text)
  586.  
  587. UBYTE *text;
  588. {
  589.     UBYTE *buffer;
  590.  
  591.     if (buffer = AllocVec(80, MEMF_PUBLIC | MEMF_CLEAR)) {
  592.  
  593.         buffer[1] = '\30';
  594.         buffer[2] = '\25';
  595.  
  596.         strcpy(buffer + 3, text);
  597.  
  598.         DisplayAlert(RECOVERY_ALERT, buffer, 40);
  599.  
  600.         FreeVec(buffer);
  601.     }
  602. }
  603.  
  604. ///
  605.